From 66c5bb20f8dd389496c40635625ae1132cdc686f Mon Sep 17 00:00:00 2001
From: Myy <myy@miouyouyou.fr>
Date: Sun, 30 Jul 2017 17:01:33 +0000
Subject: [PATCH 1/9] fbdev: Mali: Add the FBIOGET_DMABUF interface

I don't know if this interface is still useful. FBDEV will soon be
FBDEAD, since everyone is switching, for valid reasons, to the DRM
and Kernel Mode Setting interface.
This was added because the Mali FBDEV drivers need this interface.
Since the Mali FBDEV drivers are the only one that are Vulkan
compatible on RK3288 boards, I'm keeping it for the moment.

So this will stay until it can't be applied anymore. At the moment,
this patch will be removed.

Details about that interface can be found here :
https://www.community.arm.com/graphics/b/blog/posts/improving-arm-mali-drivers-on-fbdev

Signed-off-by: Myy <myy@miouyouyou.fr>
---
 drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c | 21 ++++++++++++++++++
 drivers/video/fbdev/core/fbmem.c              | 31 +++++++++++++++++++++++++++
 include/linux/fb.h                            |  2 ++
 include/uapi/linux/fb.h                       |  6 ++++++
 4 files changed, 60 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
index ce946b9c..d63d0475 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
@@ -35,6 +35,26 @@ static int rockchip_fbdev_mmap(struct fb_info *info,
 	return rockchip_gem_mmap_buf(private->fbdev_bo, vma);
 }
 
+/* Mali driver specific API :
+	https://www.community.arm.com/graphics/b/blog/posts/improving-arm-mali-drivers-on-fbdev
+	I wonder if this problem isn't already solved in another way...
+ */
+static struct dma_buf *rockchip_fbdev_get_dma_buf(struct fb_info *info) {
+	struct dma_buf *buf = NULL;
+	struct drm_fb_helper *helper = info->par;
+	struct rockchip_drm_private *private = to_drm_private(helper);
+	struct drm_device *dev = helper->dev;
+
+	if (dev->driver->gem_prime_export) {
+		buf = dev->driver->gem_prime_export(dev, private->fbdev_bo, O_RDWR);
+		if (buf)
+			drm_gem_object_reference(private->fbdev_bo);
+	}
+
+	return buf;
+}
+
+
 static struct fb_ops rockchip_drm_fbdev_ops = {
 	.owner		= THIS_MODULE,
 	DRM_FB_HELPER_DEFAULT_OPS,
@@ -42,6 +62,7 @@ static struct fb_ops rockchip_drm_fbdev_ops = {
 	.fb_fillrect	= drm_fb_helper_cfb_fillrect,
 	.fb_copyarea	= drm_fb_helper_cfb_copyarea,
 	.fb_imageblit	= drm_fb_helper_cfb_imageblit,
+	.fb_dmabuf_export	= rockchip_fbdev_get_dma_buf
 };
 
 static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 7a42238d..61d1f3f8 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -31,6 +31,7 @@
 #include <linux/err.h>
 #include <linux/device.h>
 #include <linux/efi.h>
+#include <linux/dma-buf.h> // Mali specific
 #include <linux/fb.h>
 
 #include <asm/fb.h>
@@ -1084,6 +1085,21 @@ fb_blank(struct fb_info *info, int blank)
 }
 EXPORT_SYMBOL(fb_blank);
 
+/* Mali specific */
+int fb_get_dmabuf(struct fb_info *info, int flags)
+{
+	struct dma_buf *dmabuf;
+
+	if (info->fbops->fb_dmabuf_export == NULL)
+		return -ENOTTY;
+
+	dmabuf = info->fbops->fb_dmabuf_export(info);
+	if (IS_ERR(dmabuf))
+		return PTR_ERR(dmabuf);
+
+	return dma_buf_fd(dmabuf, flags);
+}
+
 static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
 			unsigned long arg)
 {
@@ -1094,6 +1110,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
 	struct fb_cmap cmap_from;
 	struct fb_cmap_user cmap;
 	struct fb_event event;
+	struct fb_dmabuf_export dmaexp;
 	void __user *argp = (void __user *)arg;
 	long ret = 0;
 
@@ -1199,6 +1216,20 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
 		unlock_fb_info(info);
 		console_unlock();
 		break;
+	case FBIOGET_DMABUF: /* Mali specific */
+		if (copy_from_user(&dmaexp, argp, sizeof(dmaexp)))
+			return -EFAULT;
+		if (!lock_fb_info(info))
+			return -ENODEV;
+		dmaexp.fd = fb_get_dmabuf(info, dmaexp.flags);
+		unlock_fb_info(info);
+
+		if (dmaexp.fd < 0)
+			return dmaexp.fd;
+
+		ret = copy_to_user(argp, &dmaexp, sizeof(dmaexp))
+		  ? -EFAULT : 0;
+		break;
 	case FBIOBLANK:
 		console_lock();
 		if (!lock_fb_info(info)) {
diff --git a/include/linux/fb.h b/include/linux/fb.h
index a964d076..37a52dbb 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -320,6 +320,8 @@ struct fb_ops {
 	/* called at KDB enter and leave time to prepare the console */
 	int (*fb_debug_enter)(struct fb_info *info);
 	int (*fb_debug_leave)(struct fb_info *info);
+
+	struct dma_buf *(*fb_dmabuf_export)(struct fb_info *info);
 };
 
 #ifdef CONFIG_FB_TILEBLITTING
diff --git a/include/uapi/linux/fb.h b/include/uapi/linux/fb.h
index fb795c3b..c279b045 100644
--- a/include/uapi/linux/fb.h
+++ b/include/uapi/linux/fb.h
@@ -34,6 +34,8 @@
 #define FBIOPUT_MODEINFO        0x4617
 #define FBIOGET_DISPINFO        0x4618
 #define FBIO_WAITFORVSYNC	_IOW('F', 0x20, __u32)
+/* Mali specific */
+#define FBIOGET_DMABUF	_IOR('F', 0x21, struct fb_dmabuf_export)
 
 #define FB_TYPE_PACKED_PIXELS		0	/* Packed Pixels	*/
 #define FB_TYPE_PLANES			1	/* Non interleaved planes */
@@ -398,5 +400,9 @@ struct fb_cursor {
 #define FB_BACKLIGHT_MAX	0xFF
 #endif
 
+struct fb_dmabuf_export { /* Mali specific */
+  __u32 fd;
+  __u32 flags;
+};
 
 #endif /* _UAPI_LINUX_FB_H */
-- 
2.13.0

